package com.sq.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author hqy
 * @version 1.0
 * @data 2019/8/31 13:45
 * @description
 */
public class JSONUtils {

    public static final String EMPTY_JSON_OBJECT_STRING = "{}";

    static {
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
    }

    public static JSONObject merge(JSONObject... jsonObjects) {
        int length;
        if (null == jsonObjects || 0 == (length = jsonObjects.length)) {
            return new JSONObject();
        }
        JSONObject base = null;
        for (int i = 1; i < length; i++) {
            JSONObject other = jsonObjects[i];
            if (null == other) {
                continue;
            }
            if (null == base) {
                base = other;
            } else {
                for (Map.Entry<String, Object> entry : other.entrySet()) {
                    base.put(entry.getKey(), entry.getValue());
                }
            }
        }
        if (null == base) {
            base = new JSONObject();
        }
        return base;
    }

    public static JSONObject merge(JSONObject base, String key, Object value) {
        if (null == base) {
            base = new JSONObject();
        }
        if (null != key) {
            base.put(key, value);
        }
        return base;
    }

    public static JSONObject merge(JSONObject base, Map<String, Object> map) {
        if (null == base) {
            base = new JSONObject();
        }
        if (null != map && !map.isEmpty()) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                base.put(entry.getKey(), entry.getValue());
            }
        }
        return base;
    }

    public static JSONObject merge(JSONObject base, Properties prop) {
        if (null == base) {
            base = new JSONObject();
        }
        if (null != prop && !prop.isEmpty()) {
            for (Map.Entry<Object, Object> entry : prop.entrySet()) {
                base.put((String) entry.getKey(), entry.getValue());
            }
        }
        return base;
    }

    public static boolean equals(JSONObject o, JSONObject ao) {
        if (null == o) {
            return null == ao;
        }
        return o.equals(ao);
    }

    public static boolean equals(JSONArray o, JSONArray ao) {
        if (null == o) {
            return null == ao;
        }
        return o.equals(ao);
    }

    public static boolean equals(JSONObject o, JSONObject ao, String[] keys) {
        if (null == o) {
            return null == ao;
        }
        if (o.equals(ao)) {
            return true;
        }
        if (null == keys || 0 == keys.length) {
            return true;
        }
        for (String key : keys) {
            Object ov = o.get(key);
            Object aov = ao.get(key);
            if (null == ov) {
                if (null != aov) {
                    return false;
                }
            } else {
                if (null == aov) {
                    return false;
                } else {
                    if (!ov.equals(aov)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    public static JSONObject clone(JSONObject o) {
        if (null == o) {
            return null;
        }
        return (JSONObject) o.clone();
    }

    public static JSONArray clone(JSONArray o) {
        if (null == o) {
            return null;
        }
        return (JSONArray) o.clone();
    }

    public static <F, T> T trans(F from, Class<T> toClass) {
        String jsonString = JSON.toJSONString(from);
        return JSON.parseObject(jsonString, toClass);
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T> T trans(Map<String, Object> from, Class<T> toClass) throws Exception {
        JSONObject json = new JSONObject(from);
        if (Map.class.isAssignableFrom(toClass)) {
            try {
                T result = toClass.newInstance();
                ((Map) result).putAll(from);
                return result;
            } catch (Exception e) {
                throw new Exception("can not instance class: " + toClass, e);
            }
        } else {
            return JSON.toJavaObject(json, toClass);
        }
    }

    public static <T> List<T> trans(List<Map<String, Object>> fromList, Class<T> toElementClass) throws Exception {
        int size = fromList.size();
        List<T> resultList = new ArrayList<T>(size);
        for (int i = 0; i < size; i++) {
            Map<String, Object> from = fromList.get(i);
            T element = null;
            if (null != from) {
                element = trans(from, toElementClass);
            }
            resultList.add(element);
        }
        return resultList;
    }

    private static final SerializerFeature[] DEFAULT_TOSTRING_FEATURES = { SerializerFeature.QuoteFieldNames,
            SerializerFeature.SkipTransientField };

    private static final SerializerFeature[] DEFAULT_PRETTY_TOSTRING_FEATURES = { SerializerFeature.QuoteFieldNames,
            SerializerFeature.SkipTransientField, SerializerFeature.PrettyFormat };

    public static String toString(Object object, boolean pretty) {
        if (!pretty) {
            return toString(object);
        }
        return JSON.toJSONString(object, DEFAULT_PRETTY_TOSTRING_FEATURES);
    }

    public static String toString(Object object) {
        return JSON.toJSONString(object, DEFAULT_TOSTRING_FEATURES);
    }


    public static <T> List<T> copy(List<?> list, Class<T> clazz){
        String oldOb = JSON.toJSONString(list);
        return JSON.parseArray(oldOb, clazz);
    }
}
